package hopfield;

import static hopfield.Configuracion.*;
import static hopfield.util.Matriz.*;

public class HopfieldMain {

	private static final int[] patron1 = { -1, -1, -1, -1 };
	private static final int[] patron2 = { 1, 1, 1, 1 };
	private static final int[][] entrada1 = { { 1, 1, 1, 1 } };
	private static final int[][] entrada2 = { { 1, 1, 1, 1 } };
	private static final int[][] entrada3 = { { 1, -1, -1, -1 } };
	private static final int[][] entrada4 = { { -1, 1, 1, 1 } };
	private static final int[][] entrada5 = { { 1, -1, -1, -1 } };
	private static final int[][] entrada6 = { { 1, 1, 1, -1 } };

	public static void main(String[] args) {
		int[][] patrones = cargarPatrones();
		int[][] identidades = iniciarIdentidades();
		int[][] pesos = calcularPesos(patrones, identidades);
		procesarEntrada(entrada1, pesos);
		procesarEntrada(entrada2, pesos);
		procesarEntrada(entrada3, pesos);
		procesarEntrada(entrada4, pesos);
		procesarEntrada(entrada5, pesos);
		procesarEntrada(entrada6, pesos);
	}

	private static int[][] cargarPatrones() {
		return new int[][] { patron1, patron2 };
	}

	private static int[][] iniciarIdentidades() {
		int[][] identidades = new int[CANT_NEURONAS][CANT_NEURONAS];
		for (int i = 0; i < CANT_FILAS - 1; i++) {
			for (int j = 0; j < CANT_COLUMNAS; j++) {
				identidades[i][j] = (i == j ? 1 : 0);
			}
		}
		return identidades;
	}

	private static int[][] calcularPesos(int[][] patrones, int[][] identidades) {
		int[][] pesos = new int[CANT_NEURONAS][CANT_NEURONAS];
		for (int i = 0; i < CANT_PATRONES; i++) {
			int[][] patron = new int[1][CANT_NEURONAS];
			for (int j = 0; j < CANT_NEURONAS; j++) {
				patron[0][j] = patrones[i][j];
				int[][] transpuesta = traspuesta(patron, CANT_FILAS, CANT_COLUMNAS);
				int[][] producto = producto(patron, transpuesta);
				int[][] opuesta = opuesta(producto);
				int[][] salida = suma(producto, opuesta);
				pesos = suma(pesos, salida);
			}
		}
		return pesos;
	}

	private static int[][] procesarEntrada(int[][] entrada, int[][] pesos) {
		int[][] salida = new int[1][CANT_NEURONAS];
		boolean igual;
		do {
			salida = producto(entrada, pesos); // t,(t+1) => 1,4
			salida = discretos(salida);
			igual = sonIguales(entrada, salida); // func escalon con
												 // desplazamiento 0 => 1,4,4
			if (igual) {
				entrada = salida;
			}
		} while (!igual);
		return salida;
	}

	private static int[][] discretos(final int[][] m) {
		for (int j = 0; j < CANT_NEURONAS; j++) {
			m[0][j] = (m[0][j] < 0 ? -1 : 1);
		}
		return m;
	}
}
